﻿using Abp.Domain.Repositories;
using Abp.UI;
using App.Authorization.Roles.Dto;
using App.BaseObject;
using App.Configuration;
using Omu.ValueInjecter;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;

namespace App.Authorization.Roles
{
    public class RoleAppService : AppServiceBase, IRoleAppService
    {
        private readonly IRepository<MenuPermission> _menuRepository;
        private readonly IRepository<Role> _roleRepository;
        private readonly IRepository<RolePermission> _rolePermissionRepository;

        public RoleAppService(
            IRepository<MenuPermission> menuRepository,
            IRepository<RolePermission> rolePermissionRepository,
            IRepository<Role> roleRepository)
        {
            _menuRepository = menuRepository;
            _roleRepository = roleRepository;
            _rolePermissionRepository = rolePermissionRepository;
        }

        public async Task<List<Role>> GetAllRole()
        {
            return await _roleRepository.GetAllIncluding(s=>s.Permissions).ToListAsync();
        }

        public async Task SaveRoleButtons(int id, BulkKeyDto<int> dto)
        {
            var role = await _roleRepository.GetAllIncluding(s=>s.Permissions).FirstOrDefaultAsync(s=>s.Id == id);
            await SetRolePermissions(role, dto.KeyList.ToArray());
        }

        public async Task<Role> GetRoleByNameAsync(string roleName)
        {
            return await _roleRepository.FirstOrDefaultAsync(s => s.RoleName == roleName);
        }

        public async Task SaveRoles(BulkDto<RoleDto> bulks)
        {
            var exists = new List<string>();
            foreach (var row in bulks.InsertedRows)
            {
                if (await _roleRepository.CountAsync(r => r.RoleName == row.RoleName) > 0)
                {
                    throw new UserFriendlyException(string.Format("名为【{0}】的角色已经存在！", row.RoleName));
                }
                else
                {
                    var role = new Role();
                    role.InjectFrom(row);
                    role.TenantId = AbpSession.TenantId;
                    _roleRepository.Insert(role);
                }
            }
            foreach (var row in bulks.UpdatedRows.Where(s => s.Id.HasValue))
            {
                var role = await _roleRepository.GetAsync(row.Id.Value);
                role.InjectFrom(row);
            }

            //删除
            foreach (var row in bulks.DeletedRows)
            {
                if (row.Id.HasValue)
                    await _roleRepository.DeleteAsync(row.Id.Value);
            }
        }

        #region set role permissions
        private async Task SetRolePermissions(Role role, int[] menuIds)
        {
            //Remove from removed roles
            foreach (var menu in await GetAllMenuByRoleId(role.Id))
            {
                var permission = await _menuRepository.GetAsync(menu.Id);
                if (menuIds.All(menuId => permission.Id != menuId))
                {
                    await RemoveFromPermissionsAsync(role.Id, menu.Id);
                }
            }

            //Add to added roles
            foreach (var menuId in menuIds)
            {
                var menu = await _menuRepository.GetAsync(menuId);
                if (role.Permissions.All(ur => ur.MenuId != menu.Id))
                {
                    await AddToPermissionsAsync(role.Id, menu.Id);
                }
            }
        }
        public async Task<List<MenuPermission>> GetAllMenuByRoleId(int roleId)
        {
            var data = new List<MenuPermission>();
            var rolePermissions = await _rolePermissionRepository.GetAllListAsync(s => s.RoleId == roleId);
            foreach (var menu in rolePermissions)
            {
                var menuPermission = _menuRepository.FirstOrDefault(menu.MenuId);
                if (menuPermission != null && data.Count(s => s.Id == menu.MenuId) == 0) data.Add(menuPermission);
            }

            return data;
        }
        private async Task AddToPermissionsAsync(int roleId, int menuId)
        {
            await _rolePermissionRepository.InsertAsync(new RolePermission { RoleId = roleId, MenuId = menuId });
        }
        private async Task RemoveFromPermissionsAsync(int roleId, int menuId)
        {
            await _rolePermissionRepository.DeleteAsync(s => s.RoleId == roleId && s.MenuId == menuId);
        }
        #endregion
    }
}
